"""
Case Type   : cm_install
Case Name   : 反复卸载安装cm后，执行gs_ctl failover操作
Create At   : 2025/4/30
Owner       : @ningyali
Description :
    1.配置xml文件中的cm相关参数
    2.反复执行卸载安装操作,最后执行安装
    3.执行多次switchover和重启命令
    4.查看数据库和cm的term值
    5.cm_ctl查看集群状态
    6.执行gs_ctl failover操作，构造双主场景
    7.稍后查看集群状态
Expect      :
    1.执行成功
    2.安装成功
    3.执行成功
    4.数据库的term值增大，cm的term值增大
    5.集群状态正常，一个主节点
    6.执行成功
    7.集群状态恢复正常，只有一个主节点
History     :
"""
import os
import time
import unittest

from testcase.utils.ComInstall import CmInstall
from testcase.utils.ComInstall import CmUnInstall
from testcase.utils.Common import Common
from testcase.utils.CommonSH import CommonSH
from testcase.utils.Constant import Constant
from testcase.utils.Logger import Logger
from yat.test import Node
from yat.test import macro


class CMInstallCase(unittest.TestCase):
    def setUp(self):
        self.log = Logger()
        self.log.info(f'----{os.path.basename(__file__)} start----')
        self.common = Common()
        self.pri_sh = CommonSH('PrimaryDbUser')
        self.root_nodes = (Node('PrimaryRoot'), Node('Standby1Root'),
                           Node('Standby2Root'))
        self.user_nodes = (Node('PrimaryDbUser'), Node('Standby1DbUser'),
                           Node('Standby2DbUser'))
        self.constant = Constant()
        self.install_pkg_path = os.path.dirname(macro.DB_SCRIPT_PATH)
        self.cm = CmInstall(self.install_pkg_path, self.pri_sh.node.ssh_user)
        self.un_cm = CmUnInstall(self.install_pkg_path,
                                 self.pri_sh.node.ssh_user)
        self.retry_num = 3
        self.ctl_ddb_cmd = f'source {macro.DB_ENV_PATH};' \
                           f'cm_ctl ddb --get / --prefix;'
        self.q_term_sql = f'select term, lsn from ' \
                          f'pg_last_xlog_replay_location();'

    def test_install(self):
        text = '----step1:配置xml文件中的cm相关参数;expect:执行成功----'
        self.log.info(text)
        self.log.info('每次cm安装前均需配置xml，故写在循环里')

        text = '----step2:反复执行卸载安装操作,最后执行安装;expect:安装成功----'
        self.log.info(text)
        db_terms = list()
        cm_terms = list()
        for i in range(self.retry_num):
            self.log.info(f'----第{i + 1}次 配置xml文件----')
            res = self.cm.update_xml_for_cm(*self.root_nodes)
            self.assertGreater(res.count('cmDir'), 1, f'执行失败: {text}')
            self.log.info(f'----第{i + 1}次 cm安装----')
            install_res = self.cm.cm_install(self.user_nodes[0])
            self.assertIn('Install CM tool success', install_res,
                          '执行失败:' + text)

            text = '----查看数据库和cm的term值----'
            self.log.info(text)
            ctl_res = self.common.get_sh_result(self.user_nodes[0],
                                                self.ctl_ddb_cmd)
            sql_res = self.pri_sh.execut_db_sql(self.q_term_sql)
            rows, _ = self.common.parse_sql_query_res(sql_res)
            db_terms.append(int(ctl_res.splitlines()[4].strip()))
            cm_terms.append(int(rows[0][0].strip()))

            if i != self.retry_num - 1:
                self.log.info(f'----第{i + 1}次 cm卸载----')
                res = self.un_cm.cm_uninstall(
                    self.user_nodes[0],
                    f'-e {macro.DB_ENV_PATH} --deleteBinary --deleteData')
                self.assertIn('Uninstall CM tool success', res, f'执行失败: {text}')

        self.log.info(f'db_terms:{db_terms}')
        self.log.info(f'cm_terms:{cm_terms}')
        self.assertEqual(len(set(db_terms)), 1, f'执行失败: {text}')
        self.assertEqual(len(set(cm_terms)), 1, f'执行失败: {text}')

        text = '----step3:执行多次switchover和重启命令;expect:执行成功----'
        self.log.info(text)
        ctl_cmd = f'source {macro.DB_ENV_PATH};' \
                  f'cm_ctl switchover -n 2 -D {macro.DB_INSTANCE_PATH};' \
                  f'cm_ctl switchover -a;' \
                  f'cm_ctl stop && cm_ctl start'
        for i in range(self.retry_num):
            self.log.info(f'----第{i + 1}次 执行switchover和重启----')
            ctl_res = self.common.get_sh_result(self.user_nodes[0], ctl_cmd)
            expect = [self.constant.cm_switchover_success_msg in ctl_res,
                      self.constant.cm_stop_success_msg in ctl_res,
                      self.constant.cm_start_success_msg in ctl_res]
            self.assertTrue(all(expect), "执行失败:" + text)

        text = '----step4:查看数据库和cm的term值;expect:数据库的term值增大，cm的term值增大----'
        self.log.info(text)
        ctl_res = self.common.get_sh_result(self.user_nodes[0],
                                            self.ctl_ddb_cmd)
        sql_res = self.pri_sh.execut_db_sql(self.q_term_sql)
        rows, _ = self.common.parse_sql_query_res(sql_res)
        db_term2 = int(ctl_res.splitlines()[4].strip())
        cm_term2 = int(rows[0][0].strip())
        self.log.info(f'db_term2 - db_term1 = {db_term2 - db_terms[0]}')
        self.log.info(f'cm_term2 - cm_term1 = {cm_term2 - cm_terms[0]}')
        self.assertGreater(db_term2 - db_terms[0], 0, "执行失败:" + text)
        self.assertGreater(cm_term2 - cm_terms[0], 0, "执行失败:" + text)

        text = '----step5:cm_ctl查看集群状态;expect:集群状态正常，一个主节点----'
        self.log.info(text)
        query_cmd = f'source {macro.DB_ENV_PATH}; cm_ctl query -Civdp'
        query_res = self.common.get_sh_result(self.user_nodes[0], query_cmd)
        self.assertEqual(query_res.count('Primary Normal'), 1, "执行失败:" + text)

        text = '----step6:执行gs_ctl failover操作，构造双主场景;expect:执行成功----'
        self.log.info(text)
        ctl_cmd = f'source {macro.DB_ENV_PATH}; ' \
                  f'gs_ctl failover -D {macro.DB_INSTANCE_PATH}'
        ctl_res = self.common.get_sh_result(self.user_nodes[1], ctl_cmd)
        self.assertIn(self.constant.FAILOVER_SUCCESS_MSG, ctl_res,
                      "执行失败:" + text)

        text = '----step7:稍后查看集群状态;expect:集群状态恢复正常，只有一个主节点----'
        self.log.info(text)
        time.sleep(10)
        query_res = self.common.get_sh_result(self.user_nodes[0], query_cmd)
        self.assertEqual(query_res.count('Primary Normal'), 1, "执行失败:" + text)

    def tearDown(self):
        text = '----poststep1:卸载cm;expect:执行成功----'
        self.log.info(text)
        self.un_cm = CmUnInstall(self.install_pkg_path,
                                 self.pri_sh.node.ssh_user)
        res = self.un_cm.cm_uninstall(
            self.user_nodes[0], '--deleteData --deleteBinary')
        self.assertIn('Uninstall CM tool success', res, f'执行失败: {text}')
        self.log.info(f'----{os.path.basename(__file__)} end----')
